package com.cjs.hegui30;

import android.app.AndroidAppHelper;
import android.content.Context;
import android.database.Cursor;
import android.os.Build;
import android.location.LocationListener;

import com.cjs.hegui30.config.PrivacyApiManager;
import com.google.gson.Gson;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

public class DumpMethodHook extends XC_MethodHook {
    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .build();

    private static final Gson gson = new Gson();
    private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
    private static final PrivacyApiManager apiManager = PrivacyApiManager.getInstance();
    private static String cachedServerUrl = null;

    public static void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
        XposedBridge.log("[Privacy] 开始初始化Hook: " + lpparam.packageName);
        addBasicHooks(lpparam);
        initializeConfiguredHooks(lpparam);
    }

    private static void addBasicHooks(XC_LoadPackage.LoadPackageParam lpparam) {
        try {
            // IMEI相关
            Class<?> telephonyManagerClass = XposedHelpers.findClass(
                    "android.telephony.TelephonyManager", lpparam.classLoader);

            // Hook无参数的方法
            hookMethod(telephonyManagerClass, "getDeviceId");
            hookMethod(telephonyManagerClass, "getImei");

            // Hook带参数的方法
            hookMethodWithParam(telephonyManagerClass, "getDeviceId", int.class);
            hookMethodWithParam(telephonyManagerClass, "getImei", int.class);

            // 位置信息相关
            Class<?> locationManagerClass = XposedHelpers.findClass(
                    "android.location.LocationManager", lpparam.classLoader);

            // 位置相关方法
            hookMethodWithParam(locationManagerClass, "getLastKnownLocation", String.class);
            XposedHelpers.findAndHookMethod(locationManagerClass, "requestLocationUpdates",
                    String.class, Long.TYPE, Float.TYPE, LocationListener.class, new DumpMethodHook());

            XposedBridge.log("[Privacy] 基础Hook设置完成");
        } catch (Throwable e) {
            XposedBridge.log("[Privacy] 设置基础Hook失败: " + e.getMessage());
        }
    }

    private static void hookMethod(Class<?> clazz, String methodName) {
        try {
            XposedHelpers.findAndHookMethod(clazz, methodName, new DumpMethodHook());
            XposedBridge.log("[Privacy] Hooked method: " + clazz.getName() + "." + methodName);
        } catch (Throwable e) {
            XposedBridge.log("[Privacy] Failed to hook method: " + clazz.getName() + "." + methodName);
        }
    }

    private static void hookMethodWithParam(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
        try {
            Object[] hookParams = new Object[parameterTypes.length + 1];
            System.arraycopy(parameterTypes, 0, hookParams, 0, parameterTypes.length);
            hookParams[parameterTypes.length] = new DumpMethodHook();

            XposedHelpers.findAndHookMethod(clazz, methodName, hookParams);
            XposedBridge.log("[Privacy] Hooked method with params: " + clazz.getName() + "." + methodName);
        } catch (Throwable e) {
            XposedBridge.log("[Privacy] Failed to hook method with params: " + clazz.getName() + "." + methodName);
        }
    }

    private static void initializeConfiguredHooks(XC_LoadPackage.LoadPackageParam lpparam) {
        XposedBridge.log("[Privacy] 开始初始化配置的Hook...");

        try {
            Map<String, PrivacyApiManager.HookConfig> configs = apiManager.getAllConfigs();
            for (Map.Entry<String, PrivacyApiManager.HookConfig> entry : configs.entrySet()) {
                String apiPath = entry.getKey();
                PrivacyApiManager.HookConfig config = entry.getValue();

                String[] parts = apiPath.split("\\.");
                String methodName = parts[parts.length - 1];
                String className = apiPath.substring(0, apiPath.length() - methodName.length() - 1);

                // 使用findClassIfExists避免类不存在时抛出异常
                Class<?> targetClass = XposedHelpers.findClassIfExists(className, lpparam.classLoader);
                if (targetClass == null) {
                    XposedBridge.log("[Privacy] 跳过不存在的类: " + className);
                    continue;
                }

                try {
                    hookMethod(targetClass, methodName);
                    XposedBridge.log("[Privacy] 成功Hook: " + config.description);
                } catch (Throwable e) {
                    XposedBridge.log("[Privacy] Hook失败(" + apiPath + "): " + e.getMessage());
                }
            }
            XposedBridge.log("[Privacy] 配置Hook初始化完成");
        } catch (Exception e) {
            XposedBridge.log("[Privacy] 配置Hook初始化错误: " + e.getMessage());
        }
    }

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        try {
            String className = param.method.getDeclaringClass().getName();
            String methodName = param.method.getName();

            Context context = AndroidAppHelper.currentApplication();
            if (context == null) {
                XposedBridge.log("[Privacy] 无法获取Context，跳过日志记录");
                return;
            }

            String serverUrl = getServerUrl(context);
            if (serverUrl == null) {
                XposedBridge.log("[Privacy] 服务器地址未配置");
                return;
            }

            // 获取参数和返回值信息
            StringBuilder paramInfo = new StringBuilder();
            if (param.args != null && param.args.length > 0) {
                paramInfo.append("Parameters: [");
                for (Object arg : param.args) {
                    paramInfo.append(arg != null ? arg.toString() : "null").append(", ");
                }
                paramInfo.setLength(paramInfo.length() - 2);
                paramInfo.append("]");
            }

            Object result = param.getResult();
            String returnValue = result != null ? result.toString() : "null";

            // 添加参数和返回值信息到堆栈跟踪
            String stackTrace = getStackTraceString(Thread.currentThread().getStackTrace());
            stackTrace += "\nParameters: " + paramInfo.toString();
            stackTrace += "\nReturn Value: " + returnValue;

            String tag = getMethodTag(className, methodName);
            sendLog(className, methodName, tag, stackTrace);

            XposedBridge.log("[Privacy] 检测到API调用: " + className + "." + methodName);
        } catch (Exception e) {
            XposedBridge.log("[Privacy] Error in afterHookedMethod: " + e.getMessage());
        }
    }

    private static String getMethodTag(String className, String methodName) {
        String fullName = className + "." + methodName;
        PrivacyApiManager.HookConfig config = apiManager.getHookConfig(fullName);
        return config != null ? config.tag : "OTHER";
    }

    private static String getStackTraceString(StackTraceElement[] elements) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : elements) {
            sb.append(element.toString()).append("\n");
        }
        return sb.toString();
    }

    private static String getServerUrl(Context context) {
        if (cachedServerUrl != null) {
            return cachedServerUrl;
        }

        try {
            if (context == null) {
                context = AndroidAppHelper.currentApplication();
                if (context == null) {
                    XposedBridge.log("[Privacy] Context not available yet");
                    return null;
                }
            }

            Cursor cursor = context.getContentResolver().query(
                    ConfigProvider.CONTENT_URI,
                    null,
                    null,
                    null,
                    null);

            if (cursor != null) {
                String address = "";
                String port = "8080";

                while (cursor.moveToNext()) {
                    String key = cursor.getString(cursor.getColumnIndex("key"));
                    String value = cursor.getString(cursor.getColumnIndex("value"));
                    if ("server_address".equals(key)) {
                        address = value;
                    } else if ("server_port".equals(key)) {
                        port = value;
                    }
                }
                cursor.close();

                if (!address.isEmpty()) {
                    cachedServerUrl = "http://" + address + ":" + port;
                    return cachedServerUrl;
                }
            }
        } catch (Exception e) {
            XposedBridge.log("[Privacy] Error getting server URL: " + e.getMessage());
        }
        return null;
    }

    private static void sendLog(String className, String methodName, String tag, String stackTrace) {
        try {
            Context context = AndroidAppHelper.currentApplication();
            if (context == null) {
                return;
            }

            String serverUrl = getServerUrl(context);
            if (serverUrl == null || serverUrl.isEmpty()) {
                return;
            }

            Map<String, String> logData = new HashMap<>();
            String packageName = AndroidAppHelper.currentApplicationInfo().packageName;
            logData.put("appPackage", packageName);
            logData.put("methodName", className + "." + methodName);
            logData.put("stackTrace", stackTrace);
            logData.put("deviceInfo",
                    "Android " + Build.VERSION.RELEASE + " (" + Build.BRAND + " " + Build.MODEL + ")");
            logData.put("tag", tag);

            String json = gson.toJson(logData);
            RequestBody body = RequestBody.create(json, JSON);
            String url = serverUrl + "/api/log";
            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();

            XposedBridge.log("[Privacy] 发送日志: " + url);

            client.newCall(request).enqueue(new okhttp3.Callback() {
                @Override
                public void onFailure(okhttp3.Call call, java.io.IOException e) {
                    XposedBridge.log("[Privacy] 发送失败: " + e.getMessage());
                }

                @Override
                public void onResponse(okhttp3.Call call, okhttp3.Response response) throws java.io.IOException {
                    XposedBridge.log("[Privacy] 发送成功，状态码: " + response.code());
                    response.close();
                }
            });

        } catch (Exception e) {
            XposedBridge.log("[Privacy] Error sending log: " + e.getMessage());
        }
    }
}
